package operativa.action;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import javax.servlet.http.HttpServletRequest;

import operativa.action.utils.UbicacionRecorrido;
import operativa.bean.entity.Location;
import operativa.model.dao.LocationDAO;
import operativa.utils.Constantes.LocationType;

import org.apache.struts2.ServletActionContext;

import algorithm.OptimalTransport;
import algorithm.TMViewRow;
import algorithm.TransportMatrix;
import algorithm.VogelAlgorithm;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.config.entities.Parameterizable;

public class TravelerAction extends ActionSupport implements Preparable, Parameterizable{
	
	private LocationDAO locationDAO = new LocationDAO();
	private static final long serialVersionUID = 1L;
	
	private Location harbor;
	private List<Location> travel = new ArrayList<Location>();
	private Map<String, UbicacionRecorrido> harborMap = new HashMap<String, UbicacionRecorrido>();
	private Map<String, UbicacionRecorrido> fishShopMap = new HashMap<String, UbicacionRecorrido>();
	private List<Location> topHarbors;
	private List<Location> topFishShops;
	private String selHarbors;
	private String selFishShops;
	private List<Location> selHarborsList = new ArrayList<Location>();
	private List<Location> selFishShopsList= new ArrayList<Location>();
	private Map<String, Object> params;

	private List<Location> harborsList = new ArrayList<Location>();
	private List<Location> fishShopsList= new ArrayList<Location>();
	private TransportMatrix matrix;
	
	@Override
	public void prepare() throws Exception {
		topHarbors = locationDAO.getByTipoUbicacion(LocationType.HARBOR.toString());
		topFishShops = locationDAO.getByTipoUbicacion(LocationType.FISHSHOP.toString());
		for (Location f : topHarbors) {
			harborMap.put(f.getId().toString(), new UbicacionRecorrido(f));
		}
		for (Location f : topFishShops) {
			fishShopMap.put(f.getId().toString(), new UbicacionRecorrido(f));
		}
	}
	
	public String init(){
		return SUCCESS;
	}
	
	public String nextStep(){
		selHarborsList = new ArrayList<Location>();
		selFishShopsList = new ArrayList<Location>();
		for (String s : harborMap.keySet()) {
			if (harborMap.get(s).getChoosen().equals("true"))
				selHarborsList.add(harborMap.get(s).getLocation());
		}
		for (String s : fishShopMap.keySet()) {
			if (fishShopMap.get(s).getChoosen().equals("true"))
				selFishShopsList.add(fishShopMap.get(s).getLocation());
		}
		if (selHarborsList.size() == 0 || selFishShopsList.size() == 0){
			return "error";
		}
		return "nextStep";
	}
	
	public String calculateModel(){
		
		
		VogelAlgorithm vogel = new VogelAlgorithm();
		
		HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST);
		//Obtengo fabricas y destinos del request
		System.out.println("HARBOR PARAMS: " + request.getParameter("selHarbors"));
		System.out.println("FISHSHOP PARAMS: " + request.getParameter("selFishShops"));
		String[] harborIds = request.getParameter("selHarbors").split(",");
		String[] fishShopIds = request.getParameter("selFishShops").split(",");
		for (int i = 0; i < harborIds.length; i++) {
			harborsList.add(locationDAO.findById(Integer.parseInt(harborIds[i]), false));
		}
		for (int i = 0; i < fishShopIds.length; i++) {
			fishShopsList.add(locationDAO.findById(Integer.parseInt(fishShopIds[i]), false));
		}
		
		//long startTime = System.currentTimeMillis();
		
		//Ejecuto el algoritmo con las fabricas y puntos de destino
		matrix = vogel.resolve(harborsList, fishShopsList);
		
		/**
		 * TODO Aca se deberia acoplar el algoritmo para sacar la mejor solucion
		 */
		
		//long middleTime = System.currentTimeMillis();
		
		OptimalTransport oT = new OptimalTransport();
		
		matrix = oT.getOptimalSolution(matrix);
		
//		long endTime = System.currentTimeMillis();
//		
//		long partialTime = middleTime - startTime;
//		long elapsedTime = endTime - startTime;

//		SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
//		dateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
//		        
//		SimpleDateFormat dateFormat2 = new SimpleDateFormat("HH:mm:ss.SSS");
//		dateFormat2.setTimeZone(TimeZone.getTimeZone("UTC"));
//		        
//		System.out.println("Start Time: " + dateFormat.format(new Date(startTime)));
//		System.out.println("End Time: " + dateFormat.format(new Date(endTime)));
//		System.out.println("Partial Time: " + dateFormat2.format(new Date(partialTime)));
//		System.out.println("Total Time: " + dateFormat2.format(new Date(elapsedTime)));
		
		//matrix.deleteFakeLocation();
		
		return SUCCESS;
	}
	
	public String getHarborListString(){
		String result = "";
		for (Location harbor : selHarborsList) {
			result+=harbor.getId().toString() + ",";			
		}
		return result.substring(0, result.length()-1);
	}
	
	public String getFishShopsListString(){
		String result = "";
		for (Location destino : selFishShopsList) {
			result+=destino.getId().toString() + ",";			
		}
		return result.substring(0, result.length()-1);
	}

	public Location getHarbor() {
		return harbor;
	}

	public void setHarbor(Location origen) {
		this.harbor = origen;
	}

	public List<Location> getTravel() {
		return travel;
	}

	public void setTravel(List<Location> recorrido) {
		this.travel = recorrido;
	}
	
	public String getHarborLocation(){
		return this.harbor.getLocation();
	}

	public LocationDAO getLocationDAO() {
		return locationDAO;
	}

	public void setLocationDAO(LocationDAO ubicacionDao) {
		this.locationDAO = ubicacionDao;
	}

	public List<Location> getHarborsList() {
		return harborsList;
	}

	public void setHarbors(List<Location> factories) {
		this.harborsList = factories;
	}

	public TransportMatrix getMatrix() {
		return matrix;
	}

	public void setMatrix(TransportMatrix matrix) {
		this.matrix = matrix;
	}
	
	public List<TMViewRow> getMatrixByRow(){
		return matrix.getMatrixByRow();
	}

	public List<Location> getFishShopsList() {
		return fishShopsList;
	}

	public void setFishShopsList(List<Location> listDestinos) {
		this.fishShopsList = listDestinos;
	}
	
	public Map<String, UbicacionRecorrido> getHarborMap() {
		return harborMap;
	}

	public Map<String, UbicacionRecorrido> getFishShopMap() {
		return fishShopMap;
	}

	public void setHarborMap(Map<String, UbicacionRecorrido> fabMap) {
		this.harborMap = fabMap;
	}

	public void setFishShopMap(Map<String, UbicacionRecorrido> destMap) {
		this.fishShopMap = destMap;
	}

	public List<Location> getTopHarbors() {
		return topHarbors;
	}

	public void setTopHarbors(List<Location> topHarbors) {
		this.topHarbors = topHarbors;
	}

	public List<Location> getTopFishShops() {
		return topFishShops;
	}

	public void setTopFishShops(List<Location> topFishShops) {
		this.topFishShops = topFishShops;
	}
	public String getSelHarbors() {
		return selHarbors;
	}

	public void setSelHarbors(String selHarbors) {
		this.selHarbors = selHarbors;
	}

	public String getSelFishShops() {
		return selFishShops;
	}

	public void setSelFishShops(String selFishShops) {
		this.selFishShops = selFishShops;
	}

	@Override
	public void addParam(String arg0, Object arg1) {
		this.params.put(arg0, arg1);
		
	}

	@Override
	public Map getParams() {
		return this.params;
	}

	@Override
	public void setParams(Map<String, Object> params) {
		this.params = params;
	}
}
